#include "quick_launch_linux.h"

#include <libgen.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <wait.h>

#include <gtk/gtk.h>

#include "npfunctions.h"

namespace quick_launch {

bool SaveLink(NativeWindow hwnd, const char* filepath, const char* exefile,
              const char* iconfile, int iconindex, const char* params) {
  FILE* fp = fopen(filepath, "w");
  if (!fp)
    return false;
  std::string buffer;
  char name[NAME_MAX] = "";
  strcpy(name, basename((char*)filepath));
  char * dot = strchr(name, '.');
  if (dot) *dot = 0;
  buffer = "[Desktop Entry]\nVersion=1.0\nName=";
  buffer += name;
  buffer += "\nGenericName=Web Browser\nComment=Access the Internet\n";
  buffer += "Exec=";
  buffer += exefile;
  buffer += " ";
  buffer += params;
  buffer += "\nTerminal=false\n";
  buffer += "Icon=";  
  buffer += iconfile;  
  buffer += "\nType=Application\nCategories=Network;WebBrowser;\n";
  buffer += "MimeType=text/html;text/xml;application/xhtml_xml;";
  buffer += "x-scheme-handler/http;x-scheme-handler/https;";
  buffer += "x-scheme-handler/ftp;";
  fwrite(buffer.c_str(), buffer.length(), 1, fp);
  fclose(fp);
  chmod(filepath, 0744);
  return true;
}

bool ResolveLink(NativeWindow hwnd, const char* lpszLinkFile,
                 std::string& path, std::string& params,
                 std::string& iconfile, int& iconindex,
                 std::string& icondata, bool resolve_icon) {
  FILE* fp = fopen(lpszLinkFile, "r");
  if (!fp)
    return false;
  
  bool ret = false;
  char buffer[4096];
  
  while(!feof(fp)) {
    if (!fgets(buffer, sizeof(buffer), fp))
      continue;
    char* temp = strchr(buffer, '\n');
    if (temp) *temp = 0;
    if (strstr(buffer, "Exec=") == buffer) {   
      char exefile[1024] = "";
      sscanf(buffer, "Exec=%s", exefile);
      path = exefile;
      params = buffer + 5 + strlen(exefile);      
      ret = true;
    } else if (strstr(buffer, "Icon=") == buffer) {
      iconindex = 0;      
      iconfile = buffer + 5;      
      if (access(iconfile.c_str(), 0) != 0) {
        iconfile = "/usr/share/icons/gnome/48x48/apps/";        
        iconfile += buffer + 5;
        iconfile += ".png";        
        if (access(iconfile.c_str(), 0) != 0) {
          iconfile = "/usr/share/icons/hicolor/48x48/apps/";
          iconfile += buffer + 5;
          iconfile += ".png";          
          if (access(iconfile.c_str(), 0) != 0) {
            ret = false;
            break;
          }
        }
        ret = true;
      }
      if (resolve_icon) {
        GetIconData(iconfile.c_str(), iconindex, icondata);
      }
    }
  }

  return ret;
}

bool DeleteQuickLaunch(NativeWindow hwnd, const char* path) {
  if (unlink(path) == 0)
    return true;
  else
    return false;
}

bool DeleteQuickLaunch(const char* path) {
  if (unlink(path) == 0)
    return true;
  else
    return false;
}

char* GetLocalPath(NativeWindow hwnd, const char* title,
                   const char* inital_path) {
  GtkWidget *dialog = gtk_file_chooser_dialog_new(
      title, NULL,
      GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
      GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
      GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);

  gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
  gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), inital_path);
  gtk_window_set_keep_above(GTK_WINDOW(dialog), TRUE);

  char* ret_value = NULL;
  if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
    char* folder = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
    if (folder) {
      int size = strlen(folder);
      ret_value = (char*)NPN_MemAlloc(size + 1);
      strcpy(ret_value, folder);
    }
    g_free(folder);
  }
  if (!ret_value) {
    if (inital_path) {
      int size = strlen(inital_path);
      ret_value = (char*)NPN_MemAlloc(size + 1);
      strcpy(ret_value, inital_path);
    } else {
      ret_value = (char*)NPN_MemAlloc(1);
      *ret_value = 0;
    }
  }
  gtk_widget_destroy(dialog);
  return ret_value;
}

bool SelectQuickLaunch(NativeWindow hwnd, char* quick_launch, int size) {
  bool ret = false;
  GtkWidget *dialog = gtk_file_chooser_dialog_new(
      "Select Desktop Entry", NULL,
      GTK_FILE_CHOOSER_ACTION_OPEN,
      GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
      GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);

  gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
  gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), "");
  GtkFileFilter* filter = gtk_file_filter_new();
  gtk_file_filter_set_name(filter, "Desktop Entry");
  gtk_file_filter_add_pattern(filter, "*.desktop");
  gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
  gtk_window_set_keep_above(GTK_WINDOW(dialog), TRUE);

  if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
    char* folder = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
    if (folder) {
      strncpy(quick_launch, folder, size - 1);
      quick_launch[size - 1] = 0;
      ret = true;
    }
    g_free(folder);    
  }
  gtk_widget_destroy(dialog);
  return ret;
}

bool Startup(NativeWindow hwnd, const char* filename) {
  std::string path;
  std::string params;
  std::string icondata;
  std::string iconfile;
  int iconindex;
  if (ResolveLink(hwnd, filename, path, params, iconfile, 
                  iconindex, icondata, false)) {
    if (fork() == 0) {
      std::string temp = params;
      params = path;
      params += temp;
      execlp("sh", "sh", "-c", params.c_str(), NULL);
      exit(1);
    }
    return true;
  }
  return false;
}

bool ValidPath(const char* path) {
  struct stat st;
  if (stat(path, &st) == 0 && S_ISDIR(st.st_mode)) {
    return true;
  }
  return false;
}

char* GetDesktopFolder(NativeWindow hwnd) {
  const char* desktop_folder = g_get_user_special_dir(G_USER_DIRECTORY_DESKTOP);
  int size = strlen(desktop_folder);
  char* return_value = (char*)NPN_MemAlloc(size + 1);
  strcpy(return_value, desktop_folder);
  return return_value;  
}

char* GetQuickLaunchFolder(NativeWindow hwnd) {
  const char* app_folder = "/usr/share/applications";
  char* path = (char*)NPN_MemAlloc(strlen(app_folder) + 1);
  strcpy(path, app_folder);
  return path;
}

char* GetDefaultDataPath(const char* exefile) {
  const char* home_dir = g_get_home_dir();
  char* path = NULL;
  if (home_dir) {
    path = (char*)NPN_MemAlloc(
        strlen(home_dir) + strlen("/.config/google-chrome") + 1);
    strcpy(path, home_dir);
    strcat(path, "/.config/google-chrome");
  }
  return path;
}

char* GetUserDataFolder() {
  const char* home_dir = g_get_home_dir();
  char* path = NULL;
  if (home_dir) {
    path = (char*)NPN_MemAlloc(
        strlen(home_dir) + strlen("/.ChromeUserData") + 1);
    strcpy(path, home_dir);
    strcat(path, "/.ChromeUserData");
  }
  return path;
}

bool CreateFolder(char* path, int size) {
  for (int index = 0; index < size; index++) {
    if (path[index] == '/') {
      path[index] = 0;
      if (!ValidPath(path)) {
        mkdir(path, 0755);
      }
      path[index] = '/';
    } else if (path[index] == 0)
      break;
  }

  if (!ValidPath(path))
    return (mkdir(path, 0755) == 0);
  else
    return true;
}

bool CopyFolder(const char* source, const char* dest) {
  int pid = fork();
  if (pid == 0) {    
    execlp("cp", "cp", "-rf", source, dest, NULL);
    exit(1);
  }
  int state = -1;
  waitpid(pid, &state, WUNTRACED);
  if (state == 0)
    return true;
  else
    return false;
}

char* GetSystemIconsPath(NativeWindow hwnd, char* path) {
  const char* home_dir = g_get_home_dir();
  if (home_dir) {
    strcpy(path, home_dir);
    strcat(path, "/ExtensionIcons/SystemIcons/");
  }
  return path;
}

char* GetUserDefinedIconsPath(NativeWindow hwnd, char* path) {
  const char* home_dir = g_get_home_dir();
  if (home_dir) {
    strcpy(path, home_dir);
    strcat(path, "/ExtensionIcons/UserDefined/");
  }
  return path;
}

void GetIconData(const char* iconfile, int index, std::string& icondata) {
  FILE* f = _tfopen(iconfile, _T("rb"));
  if (f) {
    fseek(f, 0, SEEK_END);
    int len = ftell(f);
    fseek(f, 0, SEEK_SET);
    unsigned char* source = (unsigned char*)malloc(len);
    if (source) {
      int read_len = 0;
      while ((read_len += fread(
          source + read_len, 1, len - read_len, f)) != len) ;
      char* base64 = g_base64_encode(source, len);
      if (base64) {
        icondata += base64;
        g_free(base64);
      }
      free(source);
    }
    fclose(f);
  }
}

bool ConvertImageToIcon(const char* imagefile, const char* iconfile) {
  return CopyFile(imagefile, iconfile);
}

char* ResolveUserDataDir(const std::string& params, char* userdatadir) {
  int index = params.find("--user-data-dir=\"");
  int offset = strlen("--user-data-dir=\"");
  char end_char = '"';
  if (index == params.npos) {
    index = params.find("--user-data-dir=");
    end_char = ' ';
    offset--;
  }

  std::string user_data_dir;
  if (index != params.npos) {
    int start_index = index + offset;
    index = start_index;
    int len = params.length();
    while (index < len && params[index] != end_char)
      index++;
    user_data_dir = params.substr(start_index, index - start_index);
  }
  _tcscpy(userdatadir, user_data_dir.c_str());
  return userdatadir;
}

int GetModuleFileName(char* filename, int size) {
  int ret = -1;
  char line[1024] = "";
  static int value = 0;
  void* symbol = &value;
  FILE *file;
  char *path;
  file = fopen ("/proc/self/maps", "r");
  if (file != NULL) {
    while (!feof(file)) {
      unsigned long start, end;
      if (!fgets(line, sizeof(line), file))
        continue;
      if (!strstr(line, " rw-p ") || !strchr(line, '/'))
        continue;
      sscanf(line, "%lx-%lx ", &start, &end);
      if (symbol >= (void *)start && symbol < (void *)end) {
        char *tmp;
        size_t len;
        path = strchr (line, '/');
        tmp = strrchr (path, '\n');
        if (tmp) *tmp = 0;
        strncpy(filename, path, size - 1);
        filename[size - 1] = 0;
        ret = 0;
      }
    }
    fclose (file);
  }
  return ret;
}

int GetExeFileName(char* filename, int size) {
  int ret = -1;
  char line[1024] = "";
  void* symbol = line;
  FILE *file;
  char *path;
  file = fopen ("/proc/self/cmdline", "r");
  if (file != NULL) {
    if (fgets(line, sizeof(line), file)) {
      for(int index = 0; index < 1024; index++)
        if (line[index] == ' ') {
          line[index] = 0;
          break;
        }
      strncpy(filename, line, size - 1);
      filename[size - 1] = 0;
      ret = 0;
    }
  }
  
  return ret;  
}

bool CopyFile(const char* source, const char* dest) {
  FILE* src_file = fopen(source, "rb");
  FILE* dest_file = fopen(dest, "wb");
  bool ret = false;
  if (src_file && dest_file) {
    char buffer[1024];
    int len = fread(buffer, 1, 1024, src_file);
    while(len > 0) {
      fwrite(buffer, 1, len, dest_file);
      len = fread(buffer, 1, 1024, src_file);
    }
    ret = true;
  }
  
  if (src_file)
    fclose(src_file);
  if (dest_file)
    fclose(dest_file);
  
  return ret;
}

bool GetLocalImage(char* imagefile, int size) {
  bool ret = false;
  GtkWidget *dialog = gtk_file_chooser_dialog_new(
      "Select Image", NULL,
      GTK_FILE_CHOOSER_ACTION_OPEN,
      GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
      GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);

  gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
  gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), "");
  GtkFileFilter* filter = gtk_file_filter_new();
  gtk_file_filter_set_name(filter, "Image File");
  gtk_file_filter_add_pattern(filter, "*.png");
  gtk_file_filter_add_pattern(filter, "*.bmp");
  gtk_file_filter_add_pattern(filter, "*.jpg");
  gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
  gtk_window_set_keep_above(GTK_WINDOW(dialog), TRUE);

  if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
    char* folder = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
    if (folder) {
      strncpy(imagefile, folder, size - 1);
      imagefile[size - 1] = 0;
      ret = true;
    }
    g_free(folder);
  }
  gtk_widget_destroy(dialog);  
  return ret;
}

bool GetDefaultChromeIcon(char* iconfile) {
  bool ret = false;
  if (iconfile) {
    char exefile[PATH_MAX];    
    if (GetExeFileName(exefile, PATH_MAX) == 0) {
      char* dir = dirname(exefile);
      sprintf(iconfile, "%s/%s" ,dir, "product_logo_48.png");
      if (access(iconfile, 0) == 0)
        ret = true;
    }    
  }
  return ret;
}
 
}